﻿using System;
using FireStarter.Base.BusinessObjectMerger;
using FireStarterModeller.BO;
using FireStarterModeller.Logic;
using FireStarterModeller.Logic.MergeBusinessObjects;
using FireStarterModeller.Test.BO;
using Habanero.Base;
using Habanero.BO;
using Habanero.Testability;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarterModeller.Test.Logic.MergeBusinessObjects
{
    [TestFixture]
    public class TestMergeDMRelationships
    {
        [TestFixtureSetUp]
        public virtual void TestFixtureSetup()
        {
            TestUtilsLogic.SetupFixture();
        }
        [SetUp]
        public virtual void SetupTest()
        {
            TestUtilsLogic.SetupTest();
        }

        [Test]
        public void Test_FindDMRelProp_WhenRelNameAndOwnerPropSame_ShouldFind()
        {
            //---------------Set up test pack-------------------
            MergeBO<DMRelationshipProperty> relPropMerger = (MergeBO<DMRelationshipProperty>) MergeableBORegistry.Instance.Resolve<DMRelationshipProperty>();
            var fromRelProp = CreateRelPropWithRelationship(RandomValueGen.GetRandomString(), RandomValueGen.GetRandomString());
            var toRelProp = CreateRelPropWithRelationship(fromRelProp.Relationship.RelationshipName, fromRelProp.OwnerPropertyName);
            //---------------Assert Precondition----------------
            Assert.IsNull(toRelProp.OwnerProperty);
            Assert.IsNull(fromRelProp.OwnerProperty);
            Assert.AreEqual(toRelProp.OwnerPropertyName, fromRelProp.OwnerPropertyName);
            Assert.AreEqual(toRelProp.RelationshipName, fromRelProp.RelationshipName);
            Assert.AreEqual(toRelProp.ToString(), fromRelProp.ToString());
            //---------------Execute Test ----------------------
            //relPropMerger.BusinessObject = fromRelProp;
            Func<DMRelationshipProperty, bool> matchFunction = relPropMerger.MatchBusinessObject(fromRelProp);
            var matchBusinessObject = matchFunction(toRelProp);
            //---------------Test Result -----------------------
            Assert.IsTrue(matchBusinessObject, "Rel Props should");
        }

        [Test]
        public void Test_FindDMRelProp_WhenRelNameMatchAndOwnerPropNotMatch_ShouldNotFind()
        {
            //---------------Set up test pack-------------------
            MergeBO<DMRelationshipProperty> relPropMerger = (MergeBO<DMRelationshipProperty>) MergeableBORegistry.Instance.Resolve<DMRelationshipProperty>();
            var fromRelProp = CreateRelPropWithRelationship(RandomValueGen.GetRandomString(), RandomValueGen.GetRandomString());
            var toRelProp = CreateRelPropWithRelationship(fromRelProp.Relationship.RelationshipName, RandomValueGen.GetRandomString());
            //---------------Assert Precondition----------------
            Assert.AreNotEqual(toRelProp.OwnerPropertyName, fromRelProp.OwnerPropertyName);
            Assert.AreEqual(toRelProp.RelationshipName, fromRelProp.RelationshipName);
            Assert.AreNotEqual(toRelProp.ToString(), fromRelProp.ToString());
            //---------------Execute Test ----------------------
            //relPropMerger.BusinessObject = fromRelProp;
            var function = relPropMerger.MatchBusinessObject(fromRelProp);
            var matchBusinessObject = function(toRelProp);
            //---------------Test Result -----------------------
            Assert.IsFalse(matchBusinessObject, "Rel Props should not match");
        }

        private static DMRelationshipProperty CreateRelPropWithRelationship(string relationshipName, string ownerPropName)
        {
            var fromRel = TestUtilsDMRelationship.GetTestFactory().WithValue(relationship => relationship.RelationshipName, relationshipName)
                .CreateValidBusinessObject();
            var fromRelProp = TestUtilsDMRelationshipProperty.GetTestFactory()
                .WithValue(property => property.Relationship, fromRel)
                .WithValue(property => property.Property, null).WithValue(property => property.ReverseRelationshipProperty, null)
                .CreateValidBusinessObject();
            fromRelProp.OwnerPropertyName = ownerPropName;
            return fromRelProp ;
        }

        [Test]
        public void Test_MatchBusinessObjectWhenRelationshipNameAndRelatedClassEqual_ShouldBeTrue()
        {
            //---------------Set up test pack-------------------
            DMRelationship fromRelationship = MockRepository.GenerateStub<DMRelationship>(ConstructForFakes.True);
            fromRelationship.RelationshipName = RandomValueGen.GetRandomString();
            fromRelationship.RelatedClassName = RandomValueGen.GetRandomString();
            DMRelationship toRelationship = MockRepository.GenerateStub<DMRelationship>(ConstructForFakes.True);
            toRelationship.RelationshipName = fromRelationship.RelationshipName;
            toRelationship.RelatedClassName = fromRelationship.RelatedClassName;

            MergeBO<DMRelationship> relMerger = (MergeBO<DMRelationship>)MergeableBORegistry.Instance.Resolve<DMRelationship>();

            //---------------Assert Precondition----------------
            Assert.AreEqual(fromRelationship.RelationshipName, toRelationship.RelationshipName);
            Assert.AreEqual(fromRelationship.RelatedClassName, toRelationship.RelatedClassName);
            //---------------Execute Test ----------------------
            var function = relMerger.MatchBusinessObject(fromRelationship);
            var matchRelationship = function(toRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(matchRelationship);
        }

        [Test]
        public void Test_MatchBusinessObjectWhenRelatedClassNotEqual_ShouldBeFalse()
        {
            //---------------Set up test pack-------------------
            DMRelationship fromRelationship = MockRepository.GenerateStub<DMRelationship>(ConstructForFakes.True);
            fromRelationship.RelationshipName = RandomValueGen.GetRandomString();
            fromRelationship.RelatedClassName = RandomValueGen.GetRandomString();
            DMRelationship toRelationship = MockRepository.GenerateStub<DMRelationship>(ConstructForFakes.True);
            toRelationship.RelationshipName = fromRelationship.RelationshipName;
            toRelationship.RelatedClassName = RandomValueGen.GetRandomString();

            MergeBO<DMRelationship> relMerger = (MergeBO<DMRelationship>)MergeableBORegistry.Instance.Resolve<DMRelationship>();

            //---------------Assert Precondition----------------
            Assert.AreEqual(fromRelationship.RelationshipName, toRelationship.RelationshipName);
            Assert.AreNotEqual(fromRelationship.RelatedClassName, toRelationship.RelatedClassName);
            //---------------Execute Test ----------------------
            var function = relMerger.MatchBusinessObject(fromRelationship);
            var matchRelationship = function(toRelationship);
            //---------------Test Result -----------------------
            Assert.IsFalse(matchRelationship);
        }

        [Test]
        public void Test_MatchBusinessObjectWhenRelationshipNameNotEqual_ShouldBeFalse()
        {
            //---------------Set up test pack-------------------
            DMRelationship fromRelationship = MockRepository.GenerateStub<DMRelationship>(ConstructForFakes.True);
            fromRelationship.RelationshipName = RandomValueGen.GetRandomString();
            fromRelationship.RelatedClassName = RandomValueGen.GetRandomString();
            DMRelationship toRelationship = MockRepository.GenerateStub<DMRelationship>(ConstructForFakes.True);
            toRelationship.RelationshipName = RandomValueGen.GetRandomString();
            toRelationship.RelatedClassName = fromRelationship.RelatedClassName;

            MergeBO<DMRelationship> relMerger = (MergeBO<DMRelationship>)MergeableBORegistry.Instance.Resolve<DMRelationship>();

            //---------------Assert Precondition----------------
            Assert.AreNotEqual(fromRelationship.RelationshipName, toRelationship.RelationshipName);
            Assert.AreEqual(fromRelationship.RelatedClassName, toRelationship.RelatedClassName);
            //---------------Execute Test ----------------------
            var function = relMerger.MatchBusinessObject(fromRelationship);
            var matchRelationship = function(toRelationship);
            //---------------Test Result -----------------------
            Assert.IsFalse(matchRelationship);
        }

        [Test]
        public void Test_MergeDMClass_WithAddedRelationship_ShouldCreateMergedRelationship()
        {
            //---------------Set up test pack-------------------
            DMProperty ownerProp;
            DMClass ownerFromClass = GetClassWithOneProp(out ownerProp);
            MergeBO<DMClass> tempMerger = new MergeBO<DMClass>();
            //Create a second class that is an exact duplicate of the first class without
            // the relationships.
            DMClass ownerToClass = tempMerger.MergeBOFrom(ownerFromClass, null);
            //Add the relationships to the first class.
            DMRelationship fromRelationship = CreateRelationship(ownerFromClass);
            DMRelationshipProperty ownerRelProp = CreateRelProp(fromRelationship, ownerProp);

            SetRelatedClass(fromRelationship, ownerRelProp);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, ownerFromClass.RelationshipsDM.Count);
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);

            Assert.AreEqual(0, ownerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, ownerToClass.Properties.Count);
            //---------------Execute Test ----------------------
            MergeBO<DMClass> merger = new MergeBO<DMClass>();
            var mergedOwnerToClass = merger.MergeBOFrom(ownerFromClass, ownerToClass);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, mergedOwnerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, mergedOwnerToClass.Properties.Count);

            var toRelationship = mergedOwnerToClass.RelationshipsDM[0];
            Assert.AreEqual(toRelationship.RelationshipName, fromRelationship.RelationshipName);
            Assert.IsNull(toRelationship.ReverseRelationship, "The reverse relationship will be fixed in the Post Load Processor for now should be null");
        }

        [Test]
        public void Test_MergeRelationship_WithAddedRelProp_ShouldCreateMergedRelProp()
        {
            //---------------Set up test pack-------------------

            var fromRelationship = CreateRelationship(null);
            var toRelationship = new MergeBO<DMRelationship>().MergeBOFrom(fromRelationship, null);
            var fromRelProp = CreateRelProp(fromRelationship, TestUtilsShared.GetRandomString(), TestUtilsShared.GetRandomString());

            //---------------Assert Precondition---------------
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);
            Assert.IsNotNullOrEmpty(fromRelProp.OwnerPropertyName);
            Assert.IsNotNullOrEmpty(fromRelProp.RelatedPropertyName);

            Assert.AreEqual(0, toRelationship.RelationshipProperties.Count);
            //---------------Execute Test ----------------------
            MergeBO<DMRelationship> merger = new MergeBO<DMRelationship>();
            merger.MergeBOFrom(fromRelationship, toRelationship);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, toRelationship.RelationshipProperties.Count);
            var createdToRelProp = toRelationship.RelationshipProperties[0];

            Assert.AreEqual(fromRelProp.OwnerPropertyName, createdToRelProp.OwnerPropertyName);
            Assert.AreEqual(fromRelProp.RelatedPropertyName, createdToRelProp.RelatedPropertyName);
        }

        [Test]
        public void Test_MergeDMClass_WithAddedRelationship_ShouldCreateRelWithSpecialPropsSet()
        {
            //---------------Set up test pack-------------------
            DMProperty ownerProp;
            DMClass ownerFromClass = GetClassWithOneProp(out ownerProp);
            MergeBO<DMClass> tempMerger = new MergeBO<DMClass>();
            //Create a second class that is an exact duplicate of the first class without
            // the relationships.
            DMClass ownerToClass = tempMerger.MergeBOFrom(ownerFromClass, null);
            //Add the relationships to the first class.
            DMRelationship fromRelationship = CreateRelationship(ownerFromClass);
            DMRelationshipProperty ownerRelProp = CreateRelProp(fromRelationship, ownerProp);

            SetRelatedClass(fromRelationship, ownerRelProp);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, ownerFromClass.RelationshipsDM.Count);
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);
            Assert.IsNotNull(fromRelationship.ReverseRelationship);
            Assert.IsNotNull(fromRelationship.ReverseRelationshipName);
            Assert.IsNotNull(fromRelationship.RelatedClassName);
            Assert.IsNotNull(fromRelationship.RelatedAssemblyName);

            Assert.AreEqual(0, ownerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, ownerToClass.Properties.Count);

            //---------------Execute Test ----------------------
            var mergedOwnerToClass = new MergeBO<DMClass>().MergeBOFrom(ownerFromClass, ownerToClass);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, mergedOwnerToClass.RelationshipsDM.Count);
            var toRelationship = mergedOwnerToClass.RelationshipsDM[0];

            Assert.IsNull(toRelationship.ReverseRelationship, "The reverse relationship will be fixed in the Post Load Processor for now should be null");
            Assert.AreEqual(fromRelationship.ReverseRelationshipName, toRelationship.ReverseRelationshipName);
            Assert.AreEqual(fromRelationship.RelatedClassName, toRelationship.RelatedClassName);
            Assert.AreEqual(fromRelationship.RelatedAssemblyName, toRelationship.RelatedAssemblyName);
        }


        [Test]
        public void Test_MergeDMClass_WithAddedRelationship_ShouldCreateRelPropWithSpecialPropsSet()
        {
            //---------------Set up test pack-------------------
            DMProperty ownerProp;
            DMClass ownerFromClass = GetClassWithOneProp(out ownerProp);
            MergeBO<DMClass> tempMerger = new MergeBO<DMClass>();
            //Create a second class that is an exact duplicate of the first class without
            // the relationships.
            DMClass ownerToClass = tempMerger.MergeBOFrom(ownerFromClass, null);
            //Add the relationships to the first class.
            DMRelationship fromRelationship = CreateRelationship(ownerFromClass);
            DMRelationshipProperty ownerRelProp = CreateRelProp(fromRelationship, ownerProp);

            SetRelatedClass(fromRelationship, ownerRelProp);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, ownerFromClass.RelationshipsDM.Count);
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);
            Assert.IsNotNull(ownerRelProp.ReverseRelationshipProperty);
            Assert.IsNotNull(ownerRelProp.RelatedPropertyName);

            Assert.AreEqual(0, ownerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, ownerToClass.Properties.Count);

            //---------------Execute Test ----------------------
            var mergedOwnerToClass = new MergeBO<DMClass>().MergeBOFrom(ownerFromClass, ownerToClass);
            //---------------Test Result -----------------------
            Assert.AreEqual(1, mergedOwnerToClass.RelationshipsDM.Count);
            var toRelationship = mergedOwnerToClass.RelationshipsDM[0];


            Assert.AreEqual(1, toRelationship.RelationshipProperties.Count);
            var toRelProp = toRelationship.RelationshipProperties[0];
            Assert.IsNull(toRelProp.RelatedProperty);
            Assert.IsNull(toRelProp.ReverseRelationshipProperty);
            Assert.AreEqual(ownerRelProp.RelatedPropertyName, toRelProp.RelatedPropertyName);
        }


        [Test]
        public void Test_MergeAssembly_WithDMClassAddedRelationship_ShouldCreateRelPropWithSpecialPropsSet()
        {
            //---------------Set up test pack-------------------
            DMProperty ownerProp;
            DMClass ownerFromClass = GetClassWithOneProp(out ownerProp);
            ownerFromClass.Assembly = GetValidAssembly(null);
            MergeBO<DMClass> tempMerger = new MergeBO<DMClass>();
            //Create a second class that is an exact duplicate of the first class without
            // the relationships.
            DMClass ownerToClass = tempMerger.MergeBOFrom(ownerFromClass, null);
            ownerToClass.Assembly = GetValidAssembly(null);
            //Add the relationships to the first class.
            DMRelationship fromRelationship = CreateRelationship(ownerFromClass);
            DMRelationshipProperty ownerRelProp = CreateRelProp(fromRelationship, ownerProp);

            DMProperty relatedProp;
            DMClass relatedFromClass = GetClassWithOneProp(out relatedProp);
            relatedFromClass.Assembly = ownerFromClass.Assembly;
            SetRelatedClass(fromRelationship, relatedFromClass, ownerRelProp, relatedProp);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, ownerFromClass.RelationshipsDM.Count);
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);
            Assert.IsNotNull(ownerRelProp.ReverseRelationshipProperty);
            Assert.IsNotNull(ownerRelProp.RelatedPropertyName);

            Assert.AreEqual(0, ownerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, ownerToClass.Properties.Count);

            //---------------Execute Test ----------------------
            new MergeBO<DMAssembly>().MergeBOFrom(ownerFromClass.Assembly, ownerToClass.Assembly);
            //---------------Test Result -----------------------

            Assert.AreEqual(1, ownerToClass.RelationshipsDM.Count);
            var toRelationship = ownerToClass.RelationshipsDM[0];

            Assert.IsNull(toRelationship.ReverseRelationship, "The reverse relationship will be fixed in the Post Load Processor for now should be null");
            Assert.AreEqual(fromRelationship.ReverseRelationshipName, toRelationship.ReverseRelationshipName);
            Assert.AreEqual(fromRelationship.RelatedClassName, toRelationship.RelatedClassName);
            Assert.AreEqual(fromRelationship.RelatedAssemblyName, toRelationship.RelatedAssemblyName);

            Assert.AreEqual(1, toRelationship.RelationshipProperties.Count);
            var toRelProp = toRelationship.RelationshipProperties[0];
            Assert.IsNull(toRelProp.RelatedProperty);
            Assert.IsNull(toRelProp.ReverseRelationshipProperty);
            Assert.AreEqual(ownerRelProp.RelatedPropertyName, toRelProp.RelatedPropertyName);
        }

        [Test]
        public void Test_Accept_MergeSolution_WithDMClassAddedRelationship_ShouldCreateRelPropWithSpecialPropsSet()
        {
            //---------------Set up test pack-------------------
            DMProperty ownerProp;
            DMClass ownerFromClass = GetClassWithOneProp(out ownerProp);
            SolutionCreator creator = new SolutionCreator();
            var fromSolution = creator.CreateSolution();
            var toSolution = new MergeBO<DMSolution>().MergeBOFrom(fromSolution, null);
            ownerFromClass.Assembly = fromSolution.DefaultAssembly;

            MergeBO<DMClass> tempMerger = new MergeBO<DMClass>();
            //Create a second class that is an exact duplicate of the first class without
            // the relationships.
            DMClass ownerToClass = tempMerger.MergeBOFrom(ownerFromClass, null);

            ownerToClass.Assembly = toSolution.Assemblies[0];


            //Add the relationships to the first class.
            DMRelationship fromRelationship = CreateRelationship(ownerFromClass);
            DMRelationshipProperty ownerRelProp = CreateRelProp(fromRelationship, ownerProp);

            DMProperty relatedProp;
            DMClass relatedFromClass = GetClassWithOneProp(out relatedProp);
            relatedFromClass.Assembly = ownerFromClass.Assembly;
            SetRelatedClass(fromRelationship, relatedFromClass, ownerRelProp, relatedProp);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, ownerFromClass.RelationshipsDM.Count);
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);
            Assert.IsNotNull(ownerRelProp.ReverseRelationshipProperty);
            Assert.IsNotNull(ownerRelProp.RelatedPropertyName);
            Assert.AreEqual(2, fromSolution.Assemblies[0].Classes.Count, "Should have owner and related class for the relationship");

            Assert.AreEqual(0, ownerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, ownerToClass.Properties.Count);
            Assert.IsNotNull(ownerToClass.Assembly);
            Assert.AreSame(toSolution, ownerToClass.Solution);
            Assert.AreEqual(1, toSolution.Assemblies[0].Classes.Count, "Should have owner and related class for the relationship");
            //---------------Execute Test ----------------------
            var mergedSolution = new MergeBO<DMSolution>().MergeBOFrom(fromSolution, toSolution);
            //---------------Test Result -----------------------
            Assert.AreSame(mergedSolution, toSolution);
            Assert.AreSame(mergedSolution, ownerToClass.Solution);
            Assert.AreEqual(1, mergedSolution.Assemblies.Count);

            var mergedAssembly = mergedSolution.Assemblies[0];
            Assert.AreEqual(2, mergedAssembly.Classes.Count, "Created New Related Class");
            Assert.AreEqual(1, ownerToClass.RelationshipsDM.Count);
            var toRelationship = ownerToClass.RelationshipsDM[0];
            Assert.IsNull(toRelationship.ReverseRelationship, "The reverse relationship will be fixed in the Post Load Processor for now should be null");
            Assert.AreEqual(fromRelationship.ReverseRelationshipName, toRelationship.ReverseRelationshipName);
            Assert.AreEqual(fromRelationship.RelatedClassName, toRelationship.RelatedClassName);
            Assert.AreEqual(fromRelationship.RelatedAssemblyName, toRelationship.RelatedAssemblyName);

            Assert.AreEqual(1, toRelationship.RelationshipProperties.Count);
            var toRelProp = toRelationship.RelationshipProperties[0];
            Assert.IsNull(toRelProp.RelatedProperty);
            Assert.IsNotNull(toRelProp.OwnerPropertyName);
            Assert.IsNull(toRelProp.ReverseRelationshipProperty);
            Assert.AreEqual(ownerRelProp.RelatedPropertyName, toRelProp.RelatedPropertyName);

            //Check Reverse Relationship created on RelatedClass
            var relatedToClass = mergedAssembly.Classes.Find(@class => @class != ownerToClass);
            Assert.AreEqual(1, relatedToClass.RelationshipsDM.Count);
            var reverseToRelationship = relatedToClass.RelationshipsDM[0];
            Assert.AreEqual(ownerToClass.ClassNameBO, reverseToRelationship.RelatedClassName);
            Assert.IsNull(reverseToRelationship.ReverseRelationship);
            Assert.AreEqual(1, reverseToRelationship.RelationshipProperties.Count);
            var reverseToRelProp = reverseToRelationship.RelationshipProperties[0];
            Assert.IsNull(reverseToRelProp.RelatedProperty);
            Assert.IsNull(reverseToRelProp.ReverseRelationshipProperty);
            Assert.AreEqual(ownerProp.PropertyName, reverseToRelProp.RelatedPropertyName);
        }

        [Test]
        public void Test_Accept_PostLoadProcessMergedSolution_ShouldFixReverseRelationshipAndReverseRelProps()
        {
            //---------------Set up test pack-------------------
            DMProperty ownerProp;
            DMClass ownerFromClass = GetClassWithOneProp(out ownerProp);
            SolutionCreator creator = new SolutionCreator();
            var fromSolution = creator.CreateSolution();
            var toSolution = new MergeBO<DMSolution>().MergeBOFrom(fromSolution, null);
            ownerFromClass.Assembly = fromSolution.DefaultAssembly;

            MergeBO<DMClass> tempMerger = new MergeBO<DMClass>();
            //Create a second class that is an exact duplicate of the first class without
            // the relationships.
            DMClass ownerToClass = tempMerger.MergeBOFrom(ownerFromClass, null);

            ownerToClass.Assembly = toSolution.Assemblies[0];


            //Add the relationships to the first class.
            DMRelationship fromRelationship = CreateRelationship(ownerFromClass);
            DMRelationshipProperty ownerRelProp = CreateRelProp(fromRelationship, ownerProp);

            DMProperty relatedProp;
            DMClass relatedFromClass = GetClassWithOneProp(out relatedProp);
            relatedFromClass.Assembly = ownerFromClass.Assembly;
            SetRelatedClass(fromRelationship, relatedFromClass, ownerRelProp, relatedProp);

            //---------------Assert Precondition----------------
            Assert.AreEqual(1, ownerFromClass.RelationshipsDM.Count);
            Assert.AreEqual(1, fromRelationship.RelationshipProperties.Count);
            Assert.IsNotNull(ownerRelProp.ReverseRelationshipProperty);
            Assert.IsNotNull(ownerRelProp.RelatedPropertyName);
            Assert.AreEqual(2, fromSolution.Assemblies[0].Classes.Count, "Should have owner and related class for the relationship");

            Assert.AreEqual(0, ownerToClass.RelationshipsDM.Count);
            Assert.AreEqual(1, ownerToClass.Properties.Count);
            Assert.IsNotNull(ownerToClass.Assembly);
            Assert.AreSame(toSolution, ownerToClass.Solution);
            Assert.AreEqual(1, toSolution.Assemblies[0].Classes.Count, "Should have owner and related class for the relationship");
            //---------------Execute Test ----------------------
            var mergedSolution = new MergeBO<DMSolution>().MergeBOFrom(fromSolution, toSolution);
            DMSolutionPostLoadProcessor processor = new DMSolutionPostLoadProcessor(new AutoResolvingUnityContainer());
            processor.ProcessSolution(mergedSolution);
            //---------------Test Result -----------------------
            Assert.AreSame(mergedSolution, toSolution);
            Assert.AreSame(mergedSolution, ownerToClass.Solution);
            Assert.AreEqual(1, mergedSolution.Assemblies.Count);

            var mergedAssembly = mergedSolution.Assemblies[0];
            Assert.AreEqual(2, mergedAssembly.Classes.Count, "Created New Related Class");
            Assert.AreEqual(1, ownerToClass.RelationshipsDM.Count);
            var toRelationship = ownerToClass.RelationshipsDM[0];
            Assert.IsNotNull(toRelationship.ReverseRelationship, "The reverse relationship should be fixed in the Post Load Processor");

            Assert.AreEqual(1, toRelationship.RelationshipProperties.Count);
            var toRelProp = toRelationship.RelationshipProperties[0];
            Assert.AreEqual(ownerRelProp.RelatedPropertyName, toRelProp.RelatedPropertyName);
            Assert.IsNotNull(toRelProp.RelatedProperty, "The reverse  should be fixed in the Post Load Processor");
            Assert.IsNotNull(toRelProp.ReverseRelationshipProperty, "The reverse  should be fixed in the Post Load Processor");

            //Check Reverse Relationship created on RelatedClass
            var relatedToClass = mergedAssembly.Classes.Find(@class => @class != ownerToClass);
            Assert.AreEqual(1, relatedToClass.RelationshipsDM.Count);
            var reverseToRelationship = relatedToClass.RelationshipsDM[0];
            Assert.AreEqual(ownerToClass.ClassNameBO, reverseToRelationship.RelatedClassName);
            Assert.IsNotNull(reverseToRelationship.ReverseRelationship, "The reverse relationship should be fixed in the Post Load Processor");
            Assert.AreSame(toRelationship, reverseToRelationship.ReverseRelationship, "The reverse relationship should be fixed in the Post Load Processor");
            Assert.AreEqual(1, reverseToRelationship.RelationshipProperties.Count);
            var reverseToRelProp = reverseToRelationship.RelationshipProperties[0];
            Assert.IsNotNull(reverseToRelProp.RelatedProperty, "The reverse  should be fixed in the Post Load Processorl");
            Assert.IsNotNull(reverseToRelProp.ReverseRelationshipProperty, "The reverse relationship should be fixed in the Post Load Processor");
            Assert.AreEqual(ownerProp.PropertyName, reverseToRelProp.RelatedPropertyName, "The reverse relationship should be fixed in the Post Load Processor");
        }


        private static void SetRelatedClass(DMRelationship fromRelationship, DMClass relatedFromClass, DMRelationshipProperty ownerRelProp, DMProperty relatedProp)
        {
            fromRelationship.RelatedClass = relatedFromClass;
            ownerRelProp.RelatedProperty = relatedProp;
            TestUtilsDMRelationship.GetTestFactory().UpdateCompulsoryProperties(fromRelationship.ReverseRelationship);
            fromRelationship.ReverseRelationship.RelationshipName = TestUtilsShared.GetRandomString();
        }

        private static DMAssembly GetValidAssembly(DMSolution solution)
        {
            return TestUtilsDMAssembly.GetTestFactory()
                .WithValue(assembly => assembly.Solution, solution)
                .CreateValidBusinessObject();
        }




        private static void SetRelatedClass(DMRelationship ownerRelationship, DMRelationshipProperty ownerRelProp)
        {
            DMProperty relatedProp;
            DMClass relatedFromClass = GetClassWithOneProp(out relatedProp);

            ownerRelationship.RelatedClass = relatedFromClass;
            ownerRelProp.RelatedProperty = relatedProp;
            TestUtilsDMRelationship.GetTestFactory().UpdateCompulsoryProperties(ownerRelationship.ReverseRelationship);
            ownerRelationship.ReverseRelationship.RelationshipName = TestUtilsShared.GetRandomString();
        }

        private static DMRelationship CreateRelationship(DMClass ownerFromClass)
        {
            return TestUtilsDMRelationship.GetTestFactory().WithValue(relationship => relationship.ClassDM, ownerFromClass)
                .CreateValidBusinessObject();
        }

        private static DMRelationshipProperty CreateRelProp(DMRelationship ownerRelationship, DMProperty ownerProp)
        {
            return TestUtilsDMRelationshipProperty.GetTestFactory()
                .WithValue(relProp => relProp.Relationship, ownerRelationship)
                .WithValue(relProp => relProp.Property, ownerProp)
                .CreateValidBusinessObject();
        }
        private static DMRelationshipProperty CreateRelProp(DMRelationship ownerRelationship, string ownerPropName, string relPropName)
        {
            var relProp = TestUtilsDMRelationshipProperty.GetTestFactory()
                .WithValue(relProp1 => relProp1.Relationship, ownerRelationship)
                .CreateValidBusinessObject();
            relProp.OwnerPropertyName= ownerPropName;
            relProp.RelatedPropertyName = relPropName;
            return relProp;
        }

        private static DMClass GetClassWithOneProp(out DMProperty dmProp)
        {
            var dmClass = TestUtilsDMClass.GetFactory()
                .WithValue(@class => @class.Assembly, null).WithValue(@class => @class.AssemblyID, null)
                .CreateValidBusinessObject();
            dmProp = TestUtilsDMProperty.CreateUnsavedValidDMProperty(dmClass);
            return dmClass;
        }

        private static DMPropRuleParameter AddCopiedPropRuleParam(DMPropRule toPropRule, DMPropRuleParameter fromPropRuleParam)
        {
            var expectedToPropRuleParam = new DMPropRuleParameter();
            expectedToPropRuleParam.KeyName = fromPropRuleParam.KeyName;
            toPropRule.PropRuleParameters.Add(expectedToPropRuleParam);
            return expectedToPropRuleParam;
        }

        private static DMPropRuleParameter CreatePropRuleParam(DMPropRule defaultPropRule)
        {
            var dmPropRuleParameter = defaultPropRule.PropRuleParameters.CreateBusinessObject();
            dmPropRuleParameter.KeyName = TestUtilsShared.GetRandomString();
            dmPropRuleParameter.Value = TestUtilsShared.GetRandomString();
            return dmPropRuleParameter;
        }
    }
    internal class MergeDMRelationshipPropertySpy : MergeDMRelationshipProperty
    {
        internal void CallMergeProperties(IBusinessObject fromMergableBo, IBusinessObject toMergableBo)
        {
            base.MergeProperties(fromMergableBo, toMergableBo);
        }
    }
}